﻿using System;
using System.Collections.Generic;
using Interfaces;

namespace Cache
{
    public class Cache : ICache
    {
        private readonly IStorageManager _storageManager;
        private readonly Dictionary<object, object> _cache;

        public Cache(IStorageManager storageManager)
        {
            _storageManager = storageManager;
            _cache = new Dictionary<object, object>();
            IsValid = true;
        }

        #region ICache Members

        public TValue Get<TKey, TValue>(TKey key)
        {
            ThrowArgumentNullExceptionIfKeyIsNull(key);

            object valueAsObject = _cache[key];

            bool isCorrectValueType = valueAsObject is TValue;
            if (!isCorrectValueType)
            {
                throw new ArgumentException(string.Format("Value is not of requested type({0}).", typeof (TValue).FullName));
            }

            return (TValue) valueAsObject;
        }

        public void Insert<TKey>(TKey key, object value)
        {
            ThrowArgumentNullExceptionIfKeyIsNull(key);

            if (_cache.ContainsKey(key))
            {
                throw new ArgumentException(string.Format("An element with the same key({0}) already exists.", key));
            }

            _cache.Add(key, value);
        }

        public void Update<TKey>(TKey key, object value)
        {
            ThrowArgumentNullExceptionIfKeyIsNull(key);
            ThrowArgumentExceptionIfKeyDoesNotExist(key);

            _cache[key] = value;
        }

        public void Delete<TKey>(TKey key)
        {
            ThrowArgumentNullExceptionIfKeyIsNull(key);
            ThrowArgumentExceptionIfKeyDoesNotExist(key);
            
            _cache.Remove(key);
        }

        public void Invalidate()
        {
            IsValid = false;
        }

        public bool IsValid { get; private set; }

        #endregion

        private void ThrowArgumentNullExceptionIfKeyIsNull<TKey>(TKey key)
        {
            if (key == null)
            {
                throw new ArgumentNullException("key", "key must not be null.");
            }
        }

        private void ThrowArgumentExceptionIfKeyDoesNotExist<TKey>(TKey key)
        {
            if (!_cache.ContainsKey(key))
            {
                throw new ArgumentException(string.Format("Key({0}) does not exist.", key));
            }
        }
    }
}